import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestRegressor
from scipy.optimize import minimize


# ======================
# 1. 大数据模拟 - 生成保险资金运用的关键数据集
# ======================
def generate_insurance_data(years=10):
    """生成模拟数据集：包含经济指标、债券收益率和保险现金流"""
    np.random.seed(42)
    import warnings
    import matplotlib.pyplot as plt
    warnings.filterwarnings("ignore")  # 清除警告日志 可以不写
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用 来 正 常 显 示 中 文 标 签
    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    # 时间序列索引
    dates = pd.date_range(end=pd.Timestamp.today(), periods=years * 12, freq='M')

    # 宏观经济指标 (GDP增长率, 通货膨胀率, 失业率)
    gdp_growth = np.random.normal(0.02, 0.005, len(dates)).cumsum() + 0.01
    inflation = np.clip(np.random.normal(0.025, 0.01, len(dates)), 0.01, 0.08)
    unemployment = np.random.normal(0.05, 0.01, len(dates))

    # 不同期限债券收益率 (1年, 5年, 10年, 30年)
    rates = {}
    for duration in [1, 5, 10, 30]:
        base_rate = 0.03 + duration / 1000
        volatility = 0.005 + duration / 10000
        rates[f'{duration}Y'] = np.clip(np.random.normal(base_rate, volatility, len(dates)), 0, 0.15)

    # 保险现金流数据 (保费收入, 理赔支出)
    premiums = np.random.lognormal(mean=8, sigma=0.2, size=len(dates))
    claims = premiums * np.random.uniform(0.6, 0.9, len(dates))

    # 构建DataFrame
    data = pd.DataFrame({
        'GDP_Growth': gdp_growth,
        'Inflation': inflation,
        'Unemployment': unemployment,
        **rates,
        'Premiums': premiums,
        'Claims': claims
    }, index=dates)

    return data


# 生成10年历史数据
insurance_data = generate_insurance_data()
print("=== 保险资产运用核心数据集(样例) ===")
print(insurance_data[['GDP_Growth', 'Inflation', '5Y', '10Y', 'Premiums']].head())


# ======================
# 2. 大数据分析 - 利率预测模型
# ======================
def build_rate_prediction_model(data, target='10Y'):
    """使用机器学习预测未来债券收益率"""
    # 特征工程: 添加滞后特征
    df = data.copy()
    for lag in [1, 3, 6, 12]:
        df[f'GDP_Lag_{lag}'] = df['GDP_Growth'].shift(lag)
        df[f'Inf_Lag_{lag}'] = df['Inflation'].shift(lag)

    # 准备训练数据
    df.dropna(inplace=True)
    X = df.drop(columns=['1Y', '5Y', '10Y', '30Y', 'Premiums', 'Claims'])
    y = df[target]

    # 训练预测模型
    model = RandomForestRegressor(n_estimators=100, random_state=42)
    model.fit(X, y)

    # 特征重要性分析
    feat_importance = pd.Series(model.feature_importances_, index=X.columns)
    print(f"\n=== {target}债券收益率预测特征重要性 ===")
    print(feat_importance.sort_values(ascending=False).head(5))

    return model


# 构建10年期国债收益率预测模型
rate_model = build_rate_prediction_model(insurance_data)


# ======================
# 3. 资产配置优化 - 手动实现投资组合优化
# ======================
def optimize_bond_portfolio(data):
    """优化债券投资组合权重"""
    # 选择债券类型作为资产类别
    bonds = ['1Y', '5Y', '10Y', '30Y']
    bond_returns = data[bonds].pct_change().dropna()

    # 计算预期收益率和协方差矩阵
    mu = bond_returns.mean().values
    cov_matrix = bond_returns.cov().values

    # 定义优化函数
    def portfolio_variance(weights):
        return weights.T @ cov_matrix @ weights

    # 约束条件
    constraints = (
        {'type': 'eq', 'fun': lambda w: np.sum(w) - 1},  # 权重和为1
        {'type': 'ineq', 'fun': lambda w: w}  # 权重非负
    )

    # 初始权重（等权重）
    init_weights = np.ones(len(bonds)) / len(bonds)

    # 优化目标：最小化波动率
    result = minimize(
        portfolio_variance,
        init_weights,
        method='SLSQP',
        constraints=constraints,
        bounds=[(0, 1) for _ in range(len(bonds))]
    )

    if not result.success:
        raise ValueError("优化失败: " + result.message)

    weights = result.x
    weights = {bond: weight for bond, weight in zip(bonds, weights)}

    print("\n=== 优化后的债券投资组合配置 ===")
    for bond, weight in weights.items():
        print(f"{bond}债券: {weight * 100:.2f}%")

    return weights


# 执行投资组合优化
portfolio_weights = optimize_bond_portfolio(insurance_data)


# ======================
# 4. 现金流匹配分析
# ======================
def cashflow_matching_analysis(data, weights):
    """模拟保险责任准备金与投资收益的现金流匹配"""
    # 计算每月可投资资金 (保费收入 - 理赔支出)
    data['Investable_Cash'] = data['Premiums'] - data['Claims']

    # 计算投资组合综合收益率
    bond_cols = ['1Y', '5Y', '10Y', '30Y']
    # 使用原始收益率数据（注意：这里不是百分比变化）
    weighted_returns = data[bond_cols].apply(lambda x: np.dot(x, list(weights.values())), axis=1)

    # 模拟投资增长 - 使用更精确的计算方法
    initial_cash = data['Investable_Cash'].iloc[0]
    portfolio_value = [initial_cash]

    # 逐月计算投资组合价值
    for i in range(1, len(data)):
        prev_value = portfolio_value[-1]
        monthly_return = weighted_returns.iloc[i] / 12  # 年化收益率转为月收益率
        new_cash = data['Investable_Cash'].iloc[i]
        new_value = prev_value * (1 + monthly_return) + new_cash
        portfolio_value.append(new_value)

    data['Portfolio_Value'] = portfolio_value

    # 计算累计可投资现金
    data['Cumulative_Cash'] = data['Investable_Cash'].cumsum()

    # 可视化结果
    plt.figure(figsize=(12, 6))
    plt.plot(data.index, data['Cumulative_Cash'], label='累计可投资现金')
    plt.plot(data.index, data['Portfolio_Value'], label='投资组合价值')
    plt.title('保险资金现金流匹配分析')
    plt.xlabel('日期')
    plt.ylabel('金额')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.savefig('insurance_cashflow_matching.png', dpi=300)
    plt.show()

    return data


# 执行现金流匹配分析
result_data = cashflow_matching_analysis(insurance_data.copy(), portfolio_weights)


# ======================
# 5. 压力测试 - 利率冲击分析
# ======================
def interest_rate_stress_test(data, weights, shock=0.02):
    """测试利率上升对投资组合的影响"""
    shock_data = data.copy()
    bond_cols = ['1Y', '5Y', '10Y', '30Y']

    # 应用利率冲击
    shock_data[bond_cols] = shock_data[bond_cols] + shock

    # 计算冲击后投资组合收益率
    weighted_returns_shock = shock_data[bond_cols].apply(lambda x: np.dot(x, list(weights.values())), axis=1)

    # 重新计算投资组合价值
    initial_cash = shock_data['Investable_Cash'].iloc[0]
    portfolio_value_shock = [initial_cash]

    for i in range(1, len(shock_data)):
        prev_value = portfolio_value_shock[-1]
        monthly_return = weighted_returns_shock.iloc[i] / 12
        new_cash = shock_data['Investable_Cash'].iloc[i]
        new_value = prev_value * (1 + monthly_return) + new_cash
        portfolio_value_shock.append(new_value)

    shock_data['Portfolio_Value_Shock'] = portfolio_value_shock

    # 提取原始组合价值和冲击后组合价值的最后一个月数据
    original_value = data['Portfolio_Value'].iloc[-1]
    shock_value = shock_data['Portfolio_Value_Shock'].iloc[-1]

    print(f"\n=== 利率上升{shock * 100}%压力测试结果 ===")
    print(f"原始组合价值: {original_value:,.2f}")
    print(f"冲击后组合价值: {shock_value:,.2f}")
    print(f"价值变动: {(shock_value - original_value) / original_value * 100:.2f}%")

    # 可视化对比
    plt.figure(figsize=(12, 6))
    plt.plot(data.index, data['Portfolio_Value'], label='原始组合价值')
    plt.plot(shock_data.index, shock_data['Portfolio_Value_Shock'], label='冲击后组合价值', linestyle='--')
    plt.title(f'利率上升{shock * 100}%对投资组合的影响')
    plt.xlabel('日期')
    plt.ylabel('组合价值')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.savefig('interest_rate_stress_test.png', dpi=300)
    plt.show()


# 执行压力测试 (利率上升2%)
interest_rate_stress_test(insurance_data.copy(), portfolio_weights)


# ======================
# 6. 资产负债久期匹配分析
# ======================
def duration_matching_analysis(weights):
    """分析资产与负债的久期匹配情况"""
    # 资产久期（基于债券期限）
    asset_duration = sum(weights[bond] * int(bond[:-1]) for bond in weights.keys())

    # 负债久期（模拟值，实际中来自保单数据）
    # 这里简化处理：假设平均负债久期为15年
    liability_duration = 15

    print("\n=== 资产负债久期匹配分析 ===")
    print(f"资产平均久期: {asset_duration:.2f}年")
    print(f"负债平均久期: {liability_duration:.2f}年")
    print(f"久期缺口: {asset_duration - liability_duration:.2f}年")

    # 可视化
    durations = [asset_duration, liability_duration]
    labels = ['资产久期', '负债久期']

    plt.figure(figsize=(8, 5))
    plt.bar(labels, durations, color=['blue', 'orange'])
    plt.title('资产负债久期匹配')
    plt.ylabel('年')
    plt.grid(axis='y')
    plt.tight_layout()
    plt.savefig('duration_matching.png', dpi=300)
    plt.show()

    return asset_duration, liability_duration


# 执行久期匹配分析
asset_dur, liability_dur = duration_matching_analysis(portfolio_weights)


# ======================
# 7. 投资组合风险分析
# ======================
def portfolio_risk_analysis(data, weights):
    """分析投资组合的风险特征"""
    bond_cols = ['1Y', '5Y', '10Y', '30Y']
    bond_returns = data[bond_cols].pct_change().dropna()

    # 计算组合收益率
    portfolio_returns = bond_returns.dot(list(weights.values()))

    # 计算风险指标
    volatility = portfolio_returns.std() * np.sqrt(12)  # 年化波动率
    sharpe_ratio = portfolio_returns.mean() / portfolio_returns.std() * np.sqrt(12)  # 年化夏普比率

    # 计算最大回撤
    cumulative_returns = (1 + portfolio_returns).cumprod()
    peak = cumulative_returns.expanding(min_periods=1).max()
    drawdown = (cumulative_returns - peak) / peak
    max_drawdown = drawdown.min()

    print("\n=== 投资组合风险分析 ===")
    print(f"年化波动率: {volatility:.4f}")
    print(f"年化夏普比率: {sharpe_ratio:.4f}")
    print(f"最大回撤: {max_drawdown:.4f}")

    # 可视化收益率分布
    plt.figure(figsize=(10, 6))
    plt.hist(portfolio_returns, bins=50, alpha=0.75, color='blue', edgecolor='black')
    plt.title('投资组合收益率分布')
    plt.xlabel('收益率')
    plt.ylabel('频率')
    plt.grid(True)
    plt.tight_layout()
    plt.savefig('returns_distribution.png', dpi=300)
    plt.show()

    return volatility, sharpe_ratio, max_drawdown


# 执行风险分析
vol, sharpe, md = portfolio_risk_analysis(insurance_data, portfolio_weights)